{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 卷积神经网络（Convolutional Neural Network, CNN）\n",
    "\n",
    "## 项目：实现一个狗品种识别算法App\n",
    "\n",
    "在这个notebook文件中，有些模板代码已经提供给你，但你还需要实现更多的功能来完成这个项目。除非有明确要求，你无须修改任何已给出的代码。以**'(练习)'**开始的标题表示接下来的代码部分中有你需要实现的功能。这些部分都配有详细的指导，需要实现的部分也会在注释中以'TODO'标出。请仔细阅读所有的提示。\n",
    "\n",
    "除了实现代码外，你还**需要**回答一些与项目及代码相关的问题。每个需要回答的问题都会以 **'问题 X'** 标记。请仔细阅读每个问题，并且在问题后的 **'回答'** 部分写出完整的答案。我们将根据 你对问题的回答 和 撰写代码实现的功能 来对你提交的项目进行评分。\n",
    "\n",
    ">**提示：**Code 和 Markdown 区域可通过 **Shift + Enter** 快捷键运行。此外，Markdown可以通过双击进入编辑模式。\n",
    "\n",
    "项目中显示为_选做_的部分可以帮助你的项目脱颖而出，而不是仅仅达到通过的最低要求。如果你决定追求更高的挑战，请在此 notebook 中完成_选做_部分的代码。\n",
    "\n",
    "---\n",
    "\n",
    "### 让我们开始吧\n",
    "在这个notebook中，你将迈出第一步，来开发可以作为移动端或 Web应用程序一部分的算法。在这个项目的最后，你的程序将能够把用户提供的任何一个图像作为输入。如果可以从图像中检测到一只狗，它会输出对狗品种的预测。如果图像中是一个人脸，它会预测一个与其最相似的狗的种类。下面这张图展示了完成项目后可能的输出结果。（……实际上我们希望每个学生的输出结果不相同！）\n",
    "\n",
    "![Sample Dog Output](images/sample_dog_output.png)\n",
    "\n",
    "在现实世界中，你需要拼凑一系列的模型来完成不同的任务；举个例子，用来预测狗种类的算法会与预测人类的算法不同。在做项目的过程中，你可能会遇到不少失败的预测，因为并不存在完美的算法和模型。你最终提交的不完美的解决方案也一定会给你带来一个有趣的学习经验！\n",
    "\n",
    "### 项目内容\n",
    "\n",
    "我们将这个notebook分为不同的步骤，你可以使用下面的链接来浏览此notebook。\n",
    "\n",
    "* [Step 0](#step0): 导入数据集\n",
    "* [Step 1](#step1): 检测人脸\n",
    "* [Step 2](#step2): 检测狗狗\n",
    "* [Step 3](#step3): 从头创建一个CNN来分类狗品种\n",
    "* [Step 4](#step4): 使用一个CNN来区分狗的品种(使用迁移学习)\n",
    "* [Step 5](#step5): 建立一个CNN来分类狗的品种（使用迁移学习）\n",
    "* [Step 6](#step6): 完成你的算法\n",
    "* [Step 7](#step7): 测试你的算法\n",
    "\n",
    "在该项目中包含了如下的问题：\n",
    "\n",
    "* [问题 1](#question1)\n",
    "* [问题 2](#question2)\n",
    "* [问题 3](#question3)\n",
    "* [问题 4](#question4)\n",
    "* [问题 5](#question5)\n",
    "* [问题 6](#question6)\n",
    "* [问题 7](#question7)\n",
    "* [问题 8](#question8)\n",
    "* [问题 9](#question9)\n",
    "* [问题 10](#question10)\n",
    "* [问题 11](#question11)\n",
    "\n",
    "\n",
    "---\n",
    "<a id='step0'></a>\n",
    "## 步骤 0: 导入数据集\n",
    "\n",
    "### 导入狗数据集\n",
    "在下方的代码单元（cell）中，我们导入了一个狗图像的数据集。我们使用 scikit-learn 库中的 `load_files` 函数来获取一些变量：\n",
    "- `train_files`, `valid_files`, `test_files` - 包含图像的文件路径的numpy数组\n",
    "- `train_targets`, `valid_targets`, `test_targets` - 包含独热编码分类标签的numpy数组\n",
    "- `dog_names` - 由字符串构成的与标签相对应的狗的种类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are 133 total dog categories.\n",
      "There are 8351 total dog images.\n",
      "\n",
      "There are 6680 training dog images.\n",
      "There are 835 validation dog images.\n",
      "There are 836 test dog images.\n"
     ]
    }
   ],
   "source": [
    "from sklearn.datasets import load_files       \n",
    "from keras.utils import np_utils\n",
    "import numpy as np\n",
    "from glob import glob\n",
    "\n",
    "# define function to load train, test, and validation datasets\n",
    "def load_dataset(path):\n",
    "    data = load_files(path)\n",
    "    dog_files = np.array(data['filenames'])\n",
    "    dog_targets = np_utils.to_categorical(np.array(data['target']), 133)\n",
    "    return dog_files, dog_targets\n",
    "\n",
    "# load train, test, and validation datasets\n",
    "train_files, train_targets = load_dataset('/data/dog_images/train')\n",
    "valid_files, valid_targets = load_dataset('/data/dog_images/valid')\n",
    "test_files, test_targets = load_dataset('/data/dog_images/test')\n",
    "\n",
    "# load list of dog names\n",
    "dog_names = [item[20:-1] for item in sorted(glob(\"/data/dog_images/train/*/\"))]\n",
    "\n",
    "# print statistics about the dataset\n",
    "print('There are %d total dog categories.' % len(dog_names))\n",
    "print('There are %s total dog images.\\n' % len(np.hstack([train_files, valid_files, test_files])))\n",
    "print('There are %d training dog images.' % len(train_files))\n",
    "print('There are %d validation dog images.' % len(valid_files))\n",
    "print('There are %d test dog images.'% len(test_files))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 导入人脸数据集\n",
    "\n",
    "在下方的代码单元中，我们导入人脸图像数据集，文件所在路径存储在名为 `human_files` 的 numpy 数组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are 13233 total human images.\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "random.seed(8675309)\n",
    "\n",
    "# 加载打乱后的人脸数据集的文件名\n",
    "human_files = np.array(glob(\"/data/lfw/*/*\"))\n",
    "random.shuffle(human_files)\n",
    "\n",
    "# 打印数据集的数据量\n",
    "print('There are %d total human images.' % len(human_files))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='step1'></a>\n",
    "## 步骤1：检测人脸\n",
    " \n",
    "我们将使用 OpenCV 中的 [Haar feature-based cascade classifiers](http://docs.opencv.org/trunk/d7/d8b/tutorial_py_face_detection.html) 来检测图像中的人脸。OpenCV 提供了很多预训练的人脸检测模型，它们以XML文件保存在 [github](https://github.com/opencv/opencv/tree/master/data/haarcascades)。我们已经下载了其中一个检测模型，并且把它存储在 `haarcascades` 的目录中。\n",
    "\n",
    "在如下代码单元中，我们将演示如何使用这个检测模型在样本图像中找到人脸。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of faces detected: 1\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f90f2cd8400>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import cv2                \n",
    "import matplotlib.pyplot as plt                        \n",
    "%matplotlib inline                               \n",
    "\n",
    "# 提取预训练的人脸检测模型\n",
    "face_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_alt.xml')\n",
    "\n",
    "# 加载彩色（通道顺序为BGR）图像\n",
    "img = cv2.imread(human_files[3])\n",
    "\n",
    "# 将BGR图像进行灰度处理\n",
    "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "\n",
    "# 在图像中找出脸\n",
    "faces = face_cascade.detectMultiScale(gray)\n",
    "\n",
    "# 打印图像中检测到的脸的个数\n",
    "print('Number of faces detected:', len(faces))\n",
    "\n",
    "# 获取每一个所检测到的脸的识别框\n",
    "for (x,y,w,h) in faces:\n",
    "    # 在人脸图像中绘制出识别框\n",
    "    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)\n",
    "    \n",
    "# 将BGR图像转变为RGB图像以打印\n",
    "cv_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n",
    "\n",
    "# 展示含有识别框的图像\n",
    "plt.imshow(cv_rgb)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在使用任何一个检测模型之前，将图像转换为灰度图是常用过程。`detectMultiScale` 函数使用储存在 `face_cascade` 中的的数据，对输入的灰度图像进行分类。\n",
    "\n",
    "在上方的代码中，`faces` 以 numpy 数组的形式，保存了识别到的面部信息。它其中每一行表示一个被检测到的脸，该数据包括如下四个信息：前两个元素  `x`、`y` 代表识别框左上角的 x 和 y 坐标（参照上图，注意 y 坐标的方向和我们默认的方向不同）；后两个元素代表识别框在 x 和 y 轴两个方向延伸的长度 `w` 和 `d`。 \n",
    "\n",
    "### 写一个人脸识别器\n",
    "\n",
    "我们可以将这个程序封装为一个函数。该函数的输入为人脸图像的**路径**，当图像中包含人脸时，该函数返回 `True`，反之返回 `False`。该函数定义如下所示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如果img_path路径表示的图像检测到了脸，返回\"True\" \n",
    "def face_detector(img_path):\n",
    "    img = cv2.imread(img_path)\n",
    "    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "    faces = face_cascade.detectMultiScale(gray)\n",
    "    return len(faces) > 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **【练习】** 评估人脸检测模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "---\n",
    "\n",
    "<a id='question1'></a>\n",
    "### __问题 1:__ \n",
    "\n",
    "在下方的代码块中，使用 `face_detector` 函数，计算：\n",
    "\n",
    "- `human_files` 的前100张图像中，能够检测到**人脸**的图像占比多少？\n",
    "- `dog_files` 的前100张图像中，能够检测到**人脸**的图像占比多少？\n",
    "\n",
    "理想情况下，人图像中检测到人脸的概率应当为100%，而狗图像中检测到人脸的概率应该为0%。你会发现我们的算法并非完美，但结果仍然是可以接受的。我们从每个数据集中提取前100个图像的文件路径，并将它们存储在`human_files_short`和`dog_files_short`中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "man detect  1.0\n",
      "dog detect  0.11\n"
     ]
    }
   ],
   "source": [
    "human_files_short = human_files[:100]\n",
    "dog_files_short = train_files[:100]\n",
    "## 请不要修改上方代码\n",
    "\n",
    "\n",
    "## TODO: 基于human_files_short和dog_files_short\n",
    "## 中的图像测试face_detector的表现\n",
    "man = 0\n",
    "dog = 0\n",
    "for i,j in zip(human_files_short,dog_files_short):\n",
    "    if face_detector(i):\n",
    "        man = man + 1\n",
    "    if face_detector(j):\n",
    "        dog = dog + 1\n",
    "print(\"man detect \",float(man/100))\n",
    "print(\"dog detect \",float(dog/100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "<a id='question2'></a>\n",
    "\n",
    "### __问题 2:__ \n",
    "\n",
    "就算法而言，该算法成功与否的关键在于，用户能否提供含有清晰面部特征的人脸图像。\n",
    "那么你认为，这样的要求在实际使用中对用户合理吗？如果你觉得不合理，你能否想到一个方法，即使图像中并没有清晰的面部特征，也能够检测到人脸？\n",
    "\n",
    "__回答:__不合理，对于像支付应用来说，人脸识别的清晰度很重要，但是对于像自动驾驶之类的行人检测来说，就不需要很清晰的人脸图像。\n",
    "使用CNN，因为对于Haar是需要有清晰的人脸图像来准确的获取特征的，这些特征都是无关的，但是CNN可以获取观察到图像中存在的关系。如果选择的特征缺乏一定的代表性来区分各个类别，模型的准确性就大打折扣，无论你采用什么样的分类策略。所以可以更有效的提高识别率。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "<a id='Selection1'></a>\n",
    "### 选做：\n",
    "\n",
    "我们建议在你的算法中使用opencv的人脸检测模型去检测人类图像，不过你可以自由地探索其他的方法，尤其是尝试使用深度学习来解决它:)。请用下方的代码单元来设计和测试你的面部监测算法。如果你决定完成这个_选做_任务，你需要报告算法在每一个数据集上的表现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "## (选做) TODO: 报告另一个面部检测算法在LFW数据集上的表现\n",
    "### 你可以随意使用所需的代码单元数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='step2'></a>\n",
    "\n",
    "## 步骤 2: 检测狗狗\n",
    "\n",
    "在这个部分中，我们使用预训练的 [ResNet-50](http://ethereon.github.io/netscope/#/gist/db945b393d40bfa26006) 模型去检测图像中的狗。下方的第一行代码就是下载了 ResNet-50 模型的网络结构参数，以及基于 [ImageNet](http://www.image-net.org/) 数据集的预训练权重。\n",
    "\n",
    "ImageNet 这目前一个非常流行的数据集，常被用来测试图像分类等计算机视觉任务相关的算法。它包含超过一千万个 URL，每一个都链接到 [1000 categories](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a) 中所对应的一个物体的图像。任给输入一个图像，该 ResNet-50 模型会返回一个对图像中物体的预测结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.applications.resnet50 import ResNet50\n",
    "\n",
    "# 定义ResNet50模型\n",
    "ResNet50_model = ResNet50(weights='imagenet')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数据预处理\n",
    "\n",
    "- 在使用 TensorFlow 作为后端的时候，在 Keras 中，CNN 的输入是一个4维数组（也被称作4维张量），它的各维度尺寸为 `(nb_samples, rows, columns, channels)`。其中 `nb_samples` 表示图像（或者样本）的总数，`rows`, `columns`, 和 `channels` 分别表示图像的行数、列数和通道数。\n",
    "\n",
    "\n",
    "- 下方的 `path_to_tensor` 函数实现如下将彩色图像的字符串型的文件路径作为输入，返回一个4维张量，作为 Keras CNN 输入。因为我们的输入图像是彩色图像，因此它们具有三个通道（ `channels` 为 `3`）。\n",
    "    1. 该函数首先读取一张图像，然后将其缩放为 224×224 的图像。\n",
    "    2. 随后，该图像被调整为具有4个维度的张量。\n",
    "    3. 对于任一输入图像，最后返回的张量的维度是：`(1, 224, 224, 3)`。\n",
    "\n",
    "\n",
    "- `paths_to_tensor` 函数将图像路径的字符串组成的 numpy 数组作为输入，并返回一个4维张量，各维度尺寸为 `(nb_samples, 224, 224, 3)`。 在这里，`nb_samples`是提供的图像路径的数据中的样本数量或图像数量。你也可以将 `nb_samples` 理解为数据集中3维张量的个数（每个3维张量表示一个不同的图像。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.preprocessing import image                  \n",
    "from tqdm import tqdm\n",
    "\n",
    "def path_to_tensor(img_path):\n",
    "    # 用PIL加载RGB图像为PIL.Image.Image类型\n",
    "    img = image.load_img(img_path, target_size=(224, 224))\n",
    "    # 将PIL.Image.Image类型转化为格式为(224, 224, 3)的3维张量\n",
    "    x = image.img_to_array(img)\n",
    "    # 将3维张量转化为格式为(1, 224, 224, 3)的4维张量并返回\n",
    "    return np.expand_dims(x, axis=0)\n",
    "\n",
    "def paths_to_tensor(img_paths):\n",
    "    list_of_tensors = [path_to_tensor(img_path) for img_path in tqdm(img_paths)]\n",
    "    return np.vstack(list_of_tensors)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 基于 ResNet-50 架构进行预测\n",
    "\n",
    "对于通过上述步骤得到的四维张量，在把它们输入到 ResNet-50 网络、或 Keras 中其他类似的预训练模型之前，还需要进行一些额外的处理：\n",
    "1. 首先，这些图像的通道顺序为 RGB，我们需要重排他们的通道顺序为 BGR。\n",
    "2. 其次，预训练模型的输入都进行了额外的归一化过程。因此我们在这里也要对这些张量进行归一化，即对所有图像所有像素都减去像素均值 `[103.939, 116.779, 123.68]`（以 RGB 模式表示，根据所有的 ImageNet 图像算出）。\n",
    "\n",
    "导入的 `preprocess_input` 函数实现了这些功能。如果你对此很感兴趣，可以在 [这里](https://github.com/fchollet/keras/blob/master/keras/applications/imagenet_utils.py) 查看 `preprocess_input`的代码。\n",
    "\n",
    "\n",
    "在实现了图像处理的部分之后，我们就可以使用模型来进行预测。这一步通过 `predict` 方法来实现，它返回一个向量，向量的第 i 个元素表示该图像属于第 i 个 ImageNet 类别的概率。这通过如下的 `ResNet50_predict_labels` 函数实现。\n",
    "\n",
    "通过对预测出的向量取用 argmax 函数（找到有最大概率值的下标序号），我们可以得到一个整数，即模型预测到的物体的类别。进而根据这个 [清单](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a)，我们能够知道这具体是哪个品种的狗狗。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.applications.resnet50 import preprocess_input, decode_predictions\n",
    "def ResNet50_predict_labels(img_path):\n",
    "    # 返回img_path路径的图像的预测向量\n",
    "    img = preprocess_input(path_to_tensor(img_path))\n",
    "    return np.argmax(ResNet50_model.predict(img))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 完成狗检测模型\n",
    "\n",
    "\n",
    "在研究该 [清单](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a) 的时候，你会注意到，狗类别对应的序号为151-268。因此，在检查预训练模型判断图像是否包含狗的时候，我们只需要检查如上的 `ResNet50_predict_labels` 函数是否返回一个介于151和268之间（包含区间端点）的值。\n",
    "\n",
    "我们通过这些想法来完成下方的 `dog_detector` 函数，如果从图像中检测到狗就返回 `True`，否则返回 `False`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def dog_detector(img_path):\n",
    "    prediction = ResNet50_predict_labels(img_path)\n",
    "    return ((prediction <= 268) & (prediction >= 151)) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 【作业】评估狗狗检测模型\n",
    "\n",
    "---\n",
    "\n",
    "<a id='question3'></a>\n",
    "### __问题 3:__ \n",
    "\n",
    "在下方的代码块中，使用 `dog_detector` 函数，计算：\n",
    "\n",
    "- `human_files_short`中图像检测到狗狗的百分比？\n",
    "- `dog_files_short`中图像检测到狗狗的百分比？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "man detect  0.0\n",
      "dog detect  1.0\n"
     ]
    }
   ],
   "source": [
    "### TODO: 测试dog_detector函数在human_files_short和dog_files_short的表现\n",
    "man = 0\n",
    "dog = 0\n",
    "for i,j in zip(human_files_short,dog_files_short):\n",
    "    if dog_detector(i):\n",
    "        man = man + 1\n",
    "    if dog_detector(j):\n",
    "        dog = dog + 1\n",
    "print(\"man detect \",float(man/100))\n",
    "print(\"dog detect \",float(dog/100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "<a id='step3'></a>\n",
    "\n",
    "## 步骤 3: 从头开始创建一个CNN来分类狗品种\n",
    "\n",
    "\n",
    "现在我们已经实现了一个函数，能够在图像中识别人类及狗狗。但我们需要更进一步的方法，来对狗的类别进行识别。在这一步中，你需要实现一个卷积神经网络来对狗的品种进行分类。你需要__从头实现__你的卷积神经网络（在这一阶段，你还不能使用迁移学习），并且你需要达到超过1%的测试集准确率。在本项目的步骤五种，你还有机会使用迁移学习来实现一个准确率大大提高的模型。\n",
    "\n",
    "在添加卷积层的时候，注意不要加上太多的（可训练的）层。更多的参数意味着更长的训练时间，也就是说你更可能需要一个 GPU 来加速训练过程。万幸的是，Keras 提供了能够轻松预测每次迭代（epoch）花费时间所需的函数。你可以据此推断你算法所需的训练时间。\n",
    "\n",
    "值得注意的是，对狗的图像进行分类是一项极具挑战性的任务。因为即便是一个正常人，也很难区分布列塔尼犬和威尔士史宾格犬。\n",
    "\n",
    "\n",
    "布列塔尼犬（Brittany） | 威尔士史宾格犬（Welsh Springer Spaniel）\n",
    "- | - \n",
    "<img src=\"images/Brittany_02625.jpg\" width=\"100\"> | <img src=\"images/Welsh_springer_spaniel_08203.jpg\" width=\"200\">\n",
    "\n",
    "不难发现其他的狗品种会有很小的类间差别（比如金毛寻回犬和美国水猎犬）。\n",
    "\n",
    "\n",
    "金毛寻回犬（Curly-Coated Retriever） | 美国水猎犬（American Water Spaniel）\n",
    "- | -\n",
    "<img src=\"images/Curly-coated_retriever_03896.jpg\" width=\"200\"> | <img src=\"images/American_water_spaniel_00648.jpg\" width=\"200\">\n",
    "\n",
    "同样，拉布拉多犬（labradors）有黄色、棕色和黑色这三种。那么你设计的基于视觉的算法将不得不克服这种较高的类间差别，以达到能够将这些不同颜色的同类狗分到同一个品种中。\n",
    "\n",
    "黄色拉布拉多犬（Yellow Labrador） | 棕色拉布拉多犬（Chocolate Labrador） | 黑色拉布拉多犬（Black Labrador）\n",
    "- | -\n",
    "<img src=\"images/Labrador_retriever_06457.jpg\" width=\"150\"> | <img src=\"images/Labrador_retriever_06455.jpg\" width=\"240\"> | <img src=\"images/Labrador_retriever_06449.jpg\" width=\"220\">\n",
    "\n",
    "我们也提到了随机分类将得到一个非常低的结果：不考虑品种略有失衡的影响，随机猜测到正确品种的概率是1/133，相对应的准确率是低于1%的。\n",
    "\n",
    "请记住，在深度学习领域，实践远远高于理论。大量尝试不同的框架吧，相信你的直觉！当然，玩得开心！\n",
    "\n",
    "\n",
    "### 数据预处理\n",
    "\n",
    "\n",
    "通过对每张图像的像素值除以255，我们对图像实现了归一化处理。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 6680/6680 [01:28<00:00, 49.68it/s] \n",
      "100%|██████████| 835/835 [00:10<00:00, 83.37it/s] \n",
      "100%|██████████| 836/836 [00:09<00:00, 84.78it/s] \n"
     ]
    }
   ],
   "source": [
    "from PIL import ImageFile                            \n",
    "ImageFile.LOAD_TRUNCATED_IMAGES = True                 \n",
    "\n",
    "# Keras中的数据预处理过程\n",
    "train_tensors = paths_to_tensor(train_files).astype('float32')/255\n",
    "valid_tensors = paths_to_tensor(valid_files).astype('float32')/255\n",
    "test_tensors = paths_to_tensor(test_files).astype('float32')/255"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 【练习】模型架构\n",
    "\n",
    "\n",
    "创建一个卷积神经网络来对狗品种进行分类。在你代码块的最后，执行 `model.summary()` 来输出你模型的总结信息。\n",
    "    \n",
    "我们已经帮你导入了一些所需的 Python 库，如有需要你可以自行导入。如果你在过程中遇到了困难，如下是给你的一点小提示——该模型能够在5个 epoch 内取得超过1%的测试准确率，并且能在CPU上很快地训练。\n",
    "\n",
    "![Sample CNN](images/sample_cnn.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "<a id='question4'></a>  \n",
    "\n",
    "### __问题 4:__ \n",
    "\n",
    "在下方的代码块中尝试使用 Keras 搭建卷积网络的架构，并回答相关的问题。\n",
    "\n",
    "1. 你可以尝试自己搭建一个卷积网络的模型，那么你需要回答你搭建卷积网络的具体步骤（用了哪些层）以及为什么这样搭建。\n",
    "2. 你也可以根据上图提示的步骤搭建卷积网络，那么请说明为何如上的架构能够在该问题上取得很好的表现。\n",
    "\n",
    "__回答:__ 使用了三层卷积层和两层maxpooling层，每一层都使用relu激活函数。\n",
    "          两层full connect层。\n",
    "          获取原图像的细节信息然后通过maxpooling获取主要细节信息，这样可以产生比较模糊的图像细节信息用来训练比较泛化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "conv2d_1 (Conv2D)            (None, 220, 220, 64)      4864      \n",
      "_________________________________________________________________\n",
      "max_pooling2d_3 (MaxPooling2 (None, 219, 219, 64)      0         \n",
      "_________________________________________________________________\n",
      "conv2d_2 (Conv2D)            (None, 215, 215, 32)      51232     \n",
      "_________________________________________________________________\n",
      "max_pooling2d_4 (MaxPooling2 (None, 214, 214, 32)      0         \n",
      "_________________________________________________________________\n",
      "conv2d_3 (Conv2D)            (None, 212, 212, 16)      4624      \n",
      "_________________________________________________________________\n",
      "global_average_pooling2d_1 ( (None, 16)                0         \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 64)                1088      \n",
      "_________________________________________________________________\n",
      "dense_2 (Dense)              (None, 133)               8645      \n",
      "=================================================================\n",
      "Total params: 70,453\n",
      "Trainable params: 70,453\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "from keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D\n",
    "from keras.layers import Dropout, Flatten, Dense\n",
    "from keras.models import Sequential\n",
    "\n",
    "model = Sequential()\n",
    "### TODO: 定义你的网络架构\n",
    "model.add(Conv2D(64,5,input_shape=(224,224,3),activation='relu'))\n",
    "model.add(MaxPooling2D(strides=1))\n",
    "model.add(Conv2D(32,5,activation='relu'))\n",
    "model.add(MaxPooling2D(strides=1))\n",
    "model.add(Conv2D(16,3,activation='relu'))\n",
    "model.add(GlobalAveragePooling2D())\n",
    "model.add(Dense(64,activation='relu'))\n",
    "model.add(Dense(133,activation='softmax'))\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 编译模型\n",
    "model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 【练习】训练模型\n",
    "\n",
    "\n",
    "---\n",
    "\n",
    "<a id='question5'></a>  \n",
    "\n",
    "### __问题 5:__ \n",
    "\n",
    "在下方代码单元训练模型。使用模型检查点（model checkpointing）来储存具有最低验证集 loss 的模型。\n",
    "\n",
    "可选题：你也可以对训练集进行 [数据增强](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html)，来优化模型的表现。\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 6680 samples, validate on 835 samples\n",
      "Epoch 1/5\n",
      "6660/6680 [============================>.] - ETA: 0s - loss: 4.8870 - acc: 0.0096Epoch 00001: val_loss improved from inf to 4.87349, saving model to saved_models/weights.best.from_scratch.hdf5\n",
      "6680/6680 [==============================] - 123s 18ms/step - loss: 4.8871 - acc: 0.0096 - val_loss: 4.8735 - val_acc: 0.0108\n",
      "Epoch 2/5\n",
      "6660/6680 [============================>.] - ETA: 0s - loss: 4.8744 - acc: 0.0104Epoch 00002: val_loss improved from 4.87349 to 4.86898, saving model to saved_models/weights.best.from_scratch.hdf5\n",
      "6680/6680 [==============================] - 120s 18ms/step - loss: 4.8744 - acc: 0.0103 - val_loss: 4.8690 - val_acc: 0.0120\n",
      "Epoch 3/5\n",
      "6660/6680 [============================>.] - ETA: 0s - loss: 4.8688 - acc: 0.0114Epoch 00003: val_loss improved from 4.86898 to 4.86194, saving model to saved_models/weights.best.from_scratch.hdf5\n",
      "6680/6680 [==============================] - 119s 18ms/step - loss: 4.8689 - acc: 0.0114 - val_loss: 4.8619 - val_acc: 0.0192\n",
      "Epoch 4/5\n",
      "6660/6680 [============================>.] - ETA: 0s - loss: 4.8468 - acc: 0.0165Epoch 00004: val_loss improved from 4.86194 to 4.81299, saving model to saved_models/weights.best.from_scratch.hdf5\n",
      "6680/6680 [==============================] - 121s 18ms/step - loss: 4.8469 - acc: 0.0165 - val_loss: 4.8130 - val_acc: 0.0180\n",
      "Epoch 5/5\n",
      "6660/6680 [============================>.] - ETA: 0s - loss: 4.7780 - acc: 0.0197Epoch 00005: val_loss improved from 4.81299 to 4.74979, saving model to saved_models/weights.best.from_scratch.hdf5\n",
      "6680/6680 [==============================] - 119s 18ms/step - loss: 4.7778 - acc: 0.0196 - val_loss: 4.7498 - val_acc: 0.0228\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.callbacks.History at 0x7f90bc600710>"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from keras.callbacks import ModelCheckpoint, History \n",
    "\n",
    "### TODO: 设置训练模型的epochs的数量\n",
    "\n",
    "epochs = 5\n",
    "\n",
    "### 不要修改下方代码\n",
    "\n",
    "checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.from_scratch.hdf5', \n",
    "                               verbose=1, save_best_only=True)\n",
    "\n",
    "model.fit(train_tensors, train_targets, \n",
    "          validation_data=(valid_tensors, valid_targets),\n",
    "          epochs=epochs, batch_size=20, callbacks=[checkpointer], verbose=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 加载具有最好验证loss的模型\n",
    "\n",
    "model.load_weights('saved_models/weights.best.from_scratch.hdf5')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 测试模型\n",
    "\n",
    "在狗图像的测试数据集上试用你的模型。确保测试准确率大于1%。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test accuracy: 3.1100%\n"
     ]
    }
   ],
   "source": [
    "# 获取测试数据集中每一个图像所预测的狗品种的index\n",
    "dog_breed_predictions = [np.argmax(model.predict(np.expand_dims(tensor, axis=0))) for tensor in test_tensors]\n",
    "\n",
    "# 报告测试准确率\n",
    "test_accuracy = 100*np.sum(np.array(dog_breed_predictions)==np.argmax(test_targets, axis=1))/len(dog_breed_predictions)\n",
    "print('Test accuracy: %.4f%%' % test_accuracy)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='step4'></a>\n",
    "## 步骤 4: 使用一个CNN来区分狗的品种\n",
    "\n",
    "\n",
    "使用 迁移学习（Transfer Learning）的方法，能帮助我们在不损失准确率的情况下大大减少训练时间。在以下步骤中，你可以尝试使用迁移学习来训练你自己的CNN。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 得到从图像中提取的特征向量（Bottleneck Features）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "bottleneck_features = np.load('/data/bottleneck_features/DogVGG16Data.npz')\n",
    "train_VGG16 = bottleneck_features['train']\n",
    "valid_VGG16 = bottleneck_features['valid']\n",
    "test_VGG16 = bottleneck_features['test']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模型架构\n",
    "\n",
    "该模型使用预训练的 VGG-16 模型作为固定的图像特征提取器，其中 VGG-16 最后一层卷积层的输出被直接输入到我们的模型。我们只需要添加一个全局平均池化层以及一个全连接层，其中全连接层使用 softmax 激活函数，对每一个狗的种类都包含一个节点。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "global_average_pooling2d_2 ( (None, 512)               0         \n",
      "_________________________________________________________________\n",
      "dense_3 (Dense)              (None, 133)               68229     \n",
      "=================================================================\n",
      "Total params: 68,229\n",
      "Trainable params: 68,229\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "VGG16_model = Sequential()\n",
    "VGG16_model.add(GlobalAveragePooling2D(input_shape=train_VGG16.shape[1:]))\n",
    "VGG16_model.add(Dense(133, activation='softmax'))\n",
    "\n",
    "VGG16_model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 编译模型\n",
    "\n",
    "VGG16_model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 6680 samples, validate on 835 samples\n",
      "Epoch 1/20\n",
      "6660/6680 [============================>.] - ETA: 0s - loss: 12.2887 - acc: 0.1173Epoch 00001: val_loss improved from inf to 10.75534, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 367us/step - loss: 12.2855 - acc: 0.1177 - val_loss: 10.7553 - val_acc: 0.2060\n",
      "Epoch 2/20\n",
      "6520/6680 [============================>.] - ETA: 0s - loss: 10.0354 - acc: 0.2836Epoch 00002: val_loss improved from 10.75534 to 10.25106, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 273us/step - loss: 10.0217 - acc: 0.2847 - val_loss: 10.2511 - val_acc: 0.2719\n",
      "Epoch 3/20\n",
      "6560/6680 [============================>.] - ETA: 0s - loss: 9.5594 - acc: 0.3476Epoch 00003: val_loss improved from 10.25106 to 9.88418, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 272us/step - loss: 9.5505 - acc: 0.3484 - val_loss: 9.8842 - val_acc: 0.3246\n",
      "Epoch 4/20\n",
      "6520/6680 [============================>.] - ETA: 0s - loss: 9.3910 - acc: 0.3799Epoch 00004: val_loss improved from 9.88418 to 9.84156, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 270us/step - loss: 9.3626 - acc: 0.3816 - val_loss: 9.8416 - val_acc: 0.3269\n",
      "Epoch 5/20\n",
      "6540/6680 [============================>.] - ETA: 0s - loss: 9.2094 - acc: 0.3943Epoch 00005: val_loss improved from 9.84156 to 9.61751, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 267us/step - loss: 9.2155 - acc: 0.3939 - val_loss: 9.6175 - val_acc: 0.3317\n",
      "Epoch 6/20\n",
      "6540/6680 [============================>.] - ETA: 0s - loss: 9.0473 - acc: 0.4109Epoch 00006: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 265us/step - loss: 9.0669 - acc: 0.4099 - val_loss: 9.6717 - val_acc: 0.3329\n",
      "Epoch 7/20\n",
      "6600/6680 [============================>.] - ETA: 0s - loss: 8.9216 - acc: 0.4220Epoch 00007: val_loss improved from 9.61751 to 9.35367, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 265us/step - loss: 8.9174 - acc: 0.4223 - val_loss: 9.3537 - val_acc: 0.3605\n",
      "Epoch 8/20\n",
      "6560/6680 [============================>.] - ETA: 0s - loss: 8.7450 - acc: 0.4380Epoch 00008: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 264us/step - loss: 8.7443 - acc: 0.4379 - val_loss: 9.3726 - val_acc: 0.3557\n",
      "Epoch 9/20\n",
      "6600/6680 [============================>.] - ETA: 0s - loss: 8.7115 - acc: 0.4465Epoch 00009: val_loss improved from 9.35367 to 9.34457, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 266us/step - loss: 8.6943 - acc: 0.4476 - val_loss: 9.3446 - val_acc: 0.3653\n",
      "Epoch 10/20\n",
      "6560/6680 [============================>.] - ETA: 0s - loss: 8.6669 - acc: 0.4517Epoch 00010: val_loss improved from 9.34457 to 9.26150, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 265us/step - loss: 8.6611 - acc: 0.4516 - val_loss: 9.2615 - val_acc: 0.3677\n",
      "Epoch 11/20\n",
      "6480/6680 [============================>.] - ETA: 0s - loss: 8.5389 - acc: 0.4531Epoch 00011: val_loss improved from 9.26150 to 9.13789, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 267us/step - loss: 8.5339 - acc: 0.4536 - val_loss: 9.1379 - val_acc: 0.3737\n",
      "Epoch 12/20\n",
      "6500/6680 [============================>.] - ETA: 0s - loss: 8.4103 - acc: 0.4626Epoch 00012: val_loss improved from 9.13789 to 9.10505, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 267us/step - loss: 8.4182 - acc: 0.4618 - val_loss: 9.1051 - val_acc: 0.3713\n",
      "Epoch 13/20\n",
      "6540/6680 [============================>.] - ETA: 0s - loss: 8.3198 - acc: 0.4671Epoch 00013: val_loss improved from 9.10505 to 8.98251, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 267us/step - loss: 8.3279 - acc: 0.4666 - val_loss: 8.9825 - val_acc: 0.3796\n",
      "Epoch 14/20\n",
      "6500/6680 [============================>.] - ETA: 0s - loss: 8.2634 - acc: 0.4752Epoch 00014: val_loss improved from 8.98251 to 8.93767, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 267us/step - loss: 8.2530 - acc: 0.4759 - val_loss: 8.9377 - val_acc: 0.3916\n",
      "Epoch 15/20\n",
      "6460/6680 [============================>.] - ETA: 0s - loss: 8.2119 - acc: 0.4834Epoch 00015: val_loss improved from 8.93767 to 8.88757, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 268us/step - loss: 8.2305 - acc: 0.4825 - val_loss: 8.8876 - val_acc: 0.3892\n",
      "Epoch 16/20\n",
      "6480/6680 [============================>.] - ETA: 0s - loss: 8.2046 - acc: 0.4838Epoch 00016: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 265us/step - loss: 8.2203 - acc: 0.4825 - val_loss: 8.9141 - val_acc: 0.3952\n",
      "Epoch 17/20\n",
      "6560/6680 [============================>.] - ETA: 0s - loss: 8.2169 - acc: 0.4835Epoch 00017: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 263us/step - loss: 8.1999 - acc: 0.4846 - val_loss: 8.9035 - val_acc: 0.3916\n",
      "Epoch 18/20\n",
      "6600/6680 [============================>.] - ETA: 0s - loss: 8.1472 - acc: 0.4850Epoch 00018: val_loss improved from 8.88757 to 8.73522, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 272us/step - loss: 8.1432 - acc: 0.4849 - val_loss: 8.7352 - val_acc: 0.4000\n",
      "Epoch 19/20\n",
      "6460/6680 [============================>.] - ETA: 0s - loss: 8.0128 - acc: 0.4957Epoch 00019: val_loss improved from 8.73522 to 8.69244, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 270us/step - loss: 8.0002 - acc: 0.4963 - val_loss: 8.6924 - val_acc: 0.4060\n",
      "Epoch 20/20\n",
      "6520/6680 [============================>.] - ETA: 0s - loss: 7.9889 - acc: 0.4971Epoch 00020: val_loss improved from 8.69244 to 8.67365, saving model to saved_models/weights.best.VGG16.hdf5\n",
      "6680/6680 [==============================] - 2s 271us/step - loss: 7.9567 - acc: 0.4991 - val_loss: 8.6737 - val_acc: 0.3928\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.callbacks.History at 0x7f90b7f3ac50>"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## 训练模型\n",
    "\n",
    "checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.VGG16.hdf5', \n",
    "                               verbose=1, save_best_only=True)\n",
    "\n",
    "VGG16_model.fit(train_VGG16, train_targets, \n",
    "          validation_data=(valid_VGG16, valid_targets),\n",
    "          epochs=20, batch_size=20, callbacks=[checkpointer], verbose=1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 加载具有最好验证loss的模型\n",
    "\n",
    "VGG16_model.load_weights('saved_models/weights.best.VGG16.hdf5')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 测试模型\n",
    "现在，我们可以测试此CNN在狗图像测试数据集中识别品种的效果如何。我们在下方打印出测试准确率。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test accuracy: 40.6699%\n"
     ]
    }
   ],
   "source": [
    "# 获取测试数据集中每一个图像所预测的狗品种的index\n",
    "VGG16_predictions = [np.argmax(VGG16_model.predict(np.expand_dims(feature, axis=0))) for feature in test_VGG16]\n",
    "\n",
    "# 报告测试准确率\n",
    "test_accuracy = 100*np.sum(np.array(VGG16_predictions)==np.argmax(test_targets, axis=1))/len(VGG16_predictions)\n",
    "print('Test accuracy: %.4f%%' % test_accuracy)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用模型预测狗的品种"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "from extract_bottleneck_features import *\n",
    "\n",
    "def VGG16_predict_breed(img_path):\n",
    "    # 提取bottleneck特征\n",
    "    bottleneck_feature = extract_VGG16(path_to_tensor(img_path))\n",
    "    # 获取预测向量\n",
    "    predicted_vector = VGG16_model.predict(bottleneck_feature)\n",
    "    # 返回此模型预测的狗的品种\n",
    "    return dog_names[np.argmax(predicted_vector)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='step5'></a>\n",
    "## 步骤 5: 建立一个CNN来分类狗的品种（使用迁移学习）\n",
    "\n",
    "现在你将使用迁移学习来建立一个CNN，从而可以从图像中识别狗的品种。你的 CNN 在测试集上的准确率必须至少达到60%。\n",
    "\n",
    "在步骤4中，我们使用了迁移学习来创建一个使用基于 VGG-16 提取的特征向量来搭建一个 CNN。在本部分内容中，你必须使用另一个预训练模型来搭建一个 CNN。为了让这个任务更易实现，我们已经预先对目前 keras 中可用的几种网络进行了预训练：\n",
    "\n",
    "- [VGG-19](https://s3-us-west-1.amazonaws.com/udacity-aind/dog-project/DogVGG19Data.npz) bottleneck features\n",
    "- [ResNet-50](https://s3-us-west-1.amazonaws.com/udacity-aind/dog-project/DogResnet50Data.npz) bottleneck features\n",
    "- [Inception](https://s3-us-west-1.amazonaws.com/udacity-aind/dog-project/DogInceptionV3Data.npz) bottleneck features\n",
    "- [Xception](https://s3-us-west-1.amazonaws.com/udacity-aind/dog-project/DogXceptionData.npz) bottleneck features\n",
    "\n",
    "这些文件被命名为为：\n",
    "\n",
    "    Dog{network}Data.npz\n",
    "\n",
    "其中 `{network}` 可以是 `VGG19`、`Resnet50`、`InceptionV3` 或 `Xception` 中的一个。选择上方网络架构中的一个，他们已经保存在目录 `/data/bottleneck_features/` 中。\n",
    "\n",
    "\n",
    "### 【练习】获取模型的特征向量\n",
    "\n",
    "在下方代码块中，通过运行下方代码提取训练、测试与验证集相对应的bottleneck特征。\n",
    "\n",
    "    bottleneck_features = np.load('/data/bottleneck_features/Dog{network}Data.npz')\n",
    "    train_{network} = bottleneck_features['train']\n",
    "    valid_{network} = bottleneck_features['valid']\n",
    "    test_{network} = bottleneck_features['test']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "### TODO: 从另一个预训练的CNN获取bottleneck特征\n",
    "bottleneck_features = np.load('/data/bottleneck_features/DogResnet50Data.npz')\n",
    "train_Resnet50 = bottleneck_features['train']\n",
    "valid_Resnet50 = bottleneck_features['valid']\n",
    "test_Resnet50 = bottleneck_features['test']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 【练习】模型架构\n",
    "\n",
    "建立一个CNN来分类狗品种。在你的代码单元块的最后，通过运行如下代码输出网络的结构：\n",
    "    \n",
    "        <your model's name>.summary()\n",
    "   \n",
    "---\n",
    "\n",
    "<a id='question6'></a>  \n",
    "\n",
    "### __问题 6:__ \n",
    "\n",
    "\n",
    "在下方的代码块中尝试使用 Keras 搭建最终的网络架构，并回答你实现最终 CNN 架构的步骤与每一步的作用，并描述你在迁移学习过程中，使用该网络架构的原因。\n",
    "\n",
    "\n",
    "__回答:__ 使用Resnet50作为迁移学习，并且增加了3层全连接层。使用迁移学习的原因是可以通过已有的经过很多数据训练好的模型加快自己的应用训练的速度并且可以获得更好的准确率。第三步中的训练时间和训练数据都没有Resnet50的多而且结构并没有像Resnet50那么好，所以训练的结果比不上迁移学习。Resnet50使用了残差单元，解决了在网络深度加深的情况下，前网络层梯度较小的问题，这歌问题会导致梯度消失。用了残差单元，可以有效的防止梯度消失问题，这样就可以训练更深的网络。\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "global_average_pooling2d_4 ( (None, 2048)              0         \n",
      "_________________________________________________________________\n",
      "dense_7 (Dense)              (None, 244)               499956    \n",
      "_________________________________________________________________\n",
      "dense_8 (Dense)              (None, 64)                15680     \n",
      "_________________________________________________________________\n",
      "dense_9 (Dense)              (None, 133)               8645      \n",
      "=================================================================\n",
      "Total params: 524,281\n",
      "Trainable params: 524,281\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "### TODO: 定义你的框架\n",
    "Res_model = Sequential()\n",
    "Res_model.add(GlobalAveragePooling2D(input_shape=train_Resnet50.shape[1:]))\n",
    "Res_model.add(Dense(244,activation='relu'))\n",
    "Res_model.add(Dense(64,activation='relu'))\n",
    "Res_model.add(Dense(133, activation='softmax'))\n",
    "\n",
    "Res_model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "### TODO: 编译模型\n",
    "Res_model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "### 【练习】训练模型\n",
    "\n",
    "<a id='question7'></a>  \n",
    "\n",
    "### __问题 7:__ \n",
    "\n",
    "在下方代码单元中训练你的模型。使用模型检查点（model checkpointing）来储存具有最低验证集 loss 的模型。\n",
    "\n",
    "当然，你也可以对训练集进行 [数据增强](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html) 以优化模型的表现，不过这不是必须的步骤。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 6680 samples, validate on 835 samples\n",
      "Epoch 1/20\n",
      "6600/6680 [============================>.] - ETA: 0s - loss: 2.6730 - acc: 0.3755Epoch 00001: val_loss improved from inf to 1.27868, saving model to saved_models/weights.best.Resnet50.hdf5\n",
      "6680/6680 [==============================] - 3s 435us/step - loss: 2.6525 - acc: 0.3795 - val_loss: 1.2787 - val_acc: 0.6263\n",
      "Epoch 2/20\n",
      "6500/6680 [============================>.] - ETA: 0s - loss: 0.8746 - acc: 0.7340Epoch 00002: val_loss improved from 1.27868 to 0.82831, saving model to saved_models/weights.best.Resnet50.hdf5\n",
      "6680/6680 [==============================] - 2s 309us/step - loss: 0.8699 - acc: 0.7338 - val_loss: 0.8283 - val_acc: 0.7401\n",
      "Epoch 3/20\n",
      "6500/6680 [============================>.] - ETA: 0s - loss: 0.5397 - acc: 0.8275Epoch 00003: val_loss improved from 0.82831 to 0.82535, saving model to saved_models/weights.best.Resnet50.hdf5\n",
      "6680/6680 [==============================] - 2s 315us/step - loss: 0.5402 - acc: 0.8280 - val_loss: 0.8253 - val_acc: 0.7665\n",
      "Epoch 4/20\n",
      "6500/6680 [============================>.] - ETA: 0s - loss: 0.3759 - acc: 0.8802Epoch 00004: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 307us/step - loss: 0.3752 - acc: 0.8798 - val_loss: 0.9152 - val_acc: 0.7234\n",
      "Epoch 5/20\n",
      "6500/6680 [============================>.] - ETA: 0s - loss: 0.2673 - acc: 0.9063Epoch 00005: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 305us/step - loss: 0.2688 - acc: 0.9063 - val_loss: 0.8925 - val_acc: 0.7689\n",
      "Epoch 6/20\n",
      "6640/6680 [============================>.] - ETA: 0s - loss: 0.1978 - acc: 0.9316Epoch 00006: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 301us/step - loss: 0.1980 - acc: 0.9317 - val_loss: 0.8976 - val_acc: 0.7689\n",
      "Epoch 7/20\n",
      "6560/6680 [============================>.] - ETA: 0s - loss: 0.1510 - acc: 0.9454Epoch 00007: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 302us/step - loss: 0.1521 - acc: 0.9455 - val_loss: 1.1792 - val_acc: 0.7461\n",
      "Epoch 8/20\n",
      "6660/6680 [============================>.] - ETA: 0s - loss: 0.1290 - acc: 0.9532Epoch 00008: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 298us/step - loss: 0.1291 - acc: 0.9530 - val_loss: 0.9878 - val_acc: 0.7820\n",
      "Epoch 9/20\n",
      "6520/6680 [============================>.] - ETA: 0s - loss: 0.0999 - acc: 0.9672Epoch 00009: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 295us/step - loss: 0.1006 - acc: 0.9668 - val_loss: 1.0848 - val_acc: 0.7760\n",
      "Epoch 10/20\n",
      "6520/6680 [============================>.] - ETA: 0s - loss: 0.0957 - acc: 0.9699Epoch 00010: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 298us/step - loss: 0.0958 - acc: 0.9698 - val_loss: 1.1747 - val_acc: 0.7701\n",
      "Epoch 11/20\n",
      "6640/6680 [============================>.] - ETA: 0s - loss: 0.0769 - acc: 0.9765Epoch 00011: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 299us/step - loss: 0.0765 - acc: 0.9766 - val_loss: 1.3031 - val_acc: 0.7677\n",
      "Epoch 12/20\n",
      "6620/6680 [============================>.] - ETA: 0s - loss: 0.0703 - acc: 0.9770Epoch 00012: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 301us/step - loss: 0.0701 - acc: 0.9771 - val_loss: 1.4015 - val_acc: 0.7677\n",
      "Epoch 13/20\n",
      "6560/6680 [============================>.] - ETA: 0s - loss: 0.0640 - acc: 0.9802Epoch 00013: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 298us/step - loss: 0.0631 - acc: 0.9804 - val_loss: 1.4114 - val_acc: 0.7677\n",
      "Epoch 14/20\n",
      "6660/6680 [============================>.] - ETA: 0s - loss: 0.0693 - acc: 0.9781Epoch 00014: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 300us/step - loss: 0.0693 - acc: 0.9781 - val_loss: 1.4295 - val_acc: 0.7629\n",
      "Epoch 15/20\n",
      "6580/6680 [============================>.] - ETA: 0s - loss: 0.0516 - acc: 0.9843Epoch 00015: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 301us/step - loss: 0.0528 - acc: 0.9840 - val_loss: 1.4438 - val_acc: 0.7701\n",
      "Epoch 16/20\n",
      "6500/6680 [============================>.] - ETA: 0s - loss: 0.0581 - acc: 0.9831Epoch 00016: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 300us/step - loss: 0.0595 - acc: 0.9822 - val_loss: 2.0099 - val_acc: 0.7353\n",
      "Epoch 17/20\n",
      "6600/6680 [============================>.] - ETA: 0s - loss: 0.0527 - acc: 0.9855Epoch 00017: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 304us/step - loss: 0.0525 - acc: 0.9855 - val_loss: 1.5723 - val_acc: 0.7653\n",
      "Epoch 18/20\n",
      "6560/6680 [============================>.] - ETA: 0s - loss: 0.0455 - acc: 0.9851Epoch 00018: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 297us/step - loss: 0.0450 - acc: 0.9852 - val_loss: 1.5810 - val_acc: 0.7928\n",
      "Epoch 19/20\n",
      "6500/6680 [============================>.] - ETA: 0s - loss: 0.0512 - acc: 0.9852Epoch 00019: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 299us/step - loss: 0.0504 - acc: 0.9853 - val_loss: 1.8603 - val_acc: 0.7641\n",
      "Epoch 20/20\n",
      "6520/6680 [============================>.] - ETA: 0s - loss: 0.0487 - acc: 0.9860Epoch 00020: val_loss did not improve\n",
      "6680/6680 [==============================] - 2s 299us/step - loss: 0.0477 - acc: 0.9864 - val_loss: 1.5258 - val_acc: 0.7832\n",
      "<keras.callbacks.History object at 0x7f90bc425978>\n"
     ]
    }
   ],
   "source": [
    "### TODO: 训练模型\n",
    "checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.Resnet50.hdf5', \n",
    "                               verbose=1, save_best_only=True)\n",
    "history = History()\n",
    "h = Res_model.fit(train_Resnet50, train_targets, \n",
    "          validation_data=(valid_Resnet50, valid_targets),\n",
    "          epochs=20, batch_size=20, callbacks=[checkpointer,history], verbose=1)\n",
    "print(h)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x7f90b4925e10>]"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f90b4a067f0>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#print(h.history['val_acc'])\n",
    "#print(h.history['acc'])\n",
    "xval = np.arange(0,20,1)\n",
    "yval = [i * 100 for i in h.history['val_acc']]\n",
    "yval2 = [i * 100 for i in h.history['acc']]\n",
    "xtick = [\"{}\".format(i) for i in xval]\n",
    "plt.xlabel('epochs')\n",
    "plt.ylabel('acc')\n",
    "plt.xticks(xval,xtick)\n",
    "plt.plot(xval,yval,color='r')\n",
    "plt.plot(xval,yval2,color='b')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "### TODO: 加载具有最佳验证loss的模型权重\n",
    "Res_model.load_weights('saved_models/weights.best.Resnet50.hdf5')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "### 【练习】测试模型\n",
    "\n",
    "<a id='question8'></a>  \n",
    "\n",
    "### __问题 8:__ \n",
    "\n",
    "在狗图像的测试数据集上试用你的模型。确保测试准确率大于60%。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test accuracy: 73.4450%\n"
     ]
    }
   ],
   "source": [
    "### TODO: 在测试集上计算分类准确率\n",
    "Res50_predictions = [np.argmax(Res_model.predict(np.expand_dims(feature, axis=0))) for feature in test_Resnet50]\n",
    "# 报告测试准确率\n",
    "test_accuracy = 100*np.sum(np.array(Res50_predictions)==np.argmax(test_targets, axis=1))/len(Res50_predictions)\n",
    "print('Test accuracy: %.4f%%' % test_accuracy)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "### 【练习】使用模型测试狗的品种\n",
    "\n",
    "\n",
    "实现一个函数，它的输入为图像路径，功能为预测对应图像的类别，输出为你模型预测出的狗类别（`Affenpinscher`, `Afghan_hound` 等）。\n",
    "\n",
    "与步骤5中的模拟函数类似，你的函数应当包含如下三个步骤：\n",
    "\n",
    "1. 根据选定的模型载入图像特征（bottleneck features）\n",
    "2. 将图像特征输输入到你的模型中，并返回预测向量。注意，在该向量上使用 argmax 函数可以返回狗种类的序号。\n",
    "3. 使用在步骤0中定义的 `dog_names` 数组来返回对应的狗种类名称。\n",
    "\n",
    "提取图像特征过程中使用到的函数可以在 `extract_bottleneck_features.py` 中找到。同时，他们应已在之前的代码块中被导入。根据你选定的 CNN 网络，你可以使用 `extract_{network}` 函数来获得对应的图像特征，其中 `{network}` 代表 `VGG19`, `Resnet50`, `InceptionV3`, 或 `Xception` 中的一个。\n",
    " \n",
    "---\n",
    "\n",
    "<a id='question9'></a>  \n",
    "\n",
    "### __问题 9:__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [],
   "source": [
    "### TODO: 写一个函数，该函数将图像的路径作为输入\n",
    "### 然后返回此模型所预测的狗的品种\n",
    "def Res50_predict_breed(img_path):\n",
    "    # 提取bottleneck特征\n",
    "    bottleneck_feature = extract_Resnet50(path_to_tensor(img_path))\n",
    "    # 获取预测向量\n",
    "    predicted_vector = Res_model.predict(bottleneck_feature)\n",
    "    # 返回此模型预测的狗的品种\n",
    "    return dog_names[np.argmax(predicted_vector)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "<a id='step6'></a>\n",
    "## 步骤 6: 完成你的算法\n",
    "\n",
    "\n",
    "\n",
    "实现一个算法，它的输入为图像的路径，它能够区分图像是否包含一个人、狗或两者都不包含，然后：\n",
    "\n",
    "- 如果从图像中检测到一只__狗__，返回被预测的品种。\n",
    "- 如果从图像中检测到__人__，返回最相像的狗品种。\n",
    "- 如果两者都不能在图像中检测到，输出错误提示。\n",
    "\n",
    "我们非常欢迎你来自己编写检测图像中人类与狗的函数，你可以随意地使用上方完成的 `face_detector` 和 `dog_detector` 函数。你__需要__在步骤5使用你的CNN来预测狗品种。\n",
    "\n",
    "下面提供了算法的示例输出，但你可以自由地设计自己的模型！\n",
    "\n",
    "![Sample Human Output](images/sample_human_output.png)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "<a id='question10'></a>  \n",
    "\n",
    "### __问题 10:__\n",
    "\n",
    "在下方代码块中完成你的代码。\n",
    "\n",
    "---\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [],
   "source": [
    "### TODO: 设计你的算法\n",
    "### 自由地使用所需的代码单元数吧\n",
    "def human_dog(img_path):\n",
    "    if face_detector(img_path):\n",
    "        return Res50_predict_breed(img_path)\n",
    "    elif dog_detector(img_path):\n",
    "        return Res50_predict_breed(img_path)\n",
    "    else:\n",
    "        return \"This is not dog or human pic\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='step7'></a>\n",
    "## 步骤 7: 测试你的算法\n",
    "\n",
    "在这个部分中，你将尝试一下你的新算法！算法认为__你__看起来像什么类型的狗？如果你有一只狗，它可以准确地预测你的狗的品种吗？如果你有一只猫，它会将你的猫误判为一只狗吗？\n",
    "\n",
    "**上传方式：点击左上角的Jupyter回到上级菜单，你可以看到Jupyter Notebook的右上方会有Upload按钮。**\n",
    "\n",
    "<a id='question11'></a>  \n",
    "\n",
    "### __问题 11:__\n",
    "\n",
    "在下方编写代码，用至少6张现实中的图片来测试你的算法。你可以使用任意照片，不过请至少使用两张人类图片（要征得当事人同意哦）和两张狗的图片。\n",
    "同时请回答如下问题：\n",
    "\n",
    "1. 输出结果比你预想的要好吗 :) ？或者更糟 :( ？\n",
    "2. 提出至少三点改进你的模型的想法。\n",
    "\n",
    "答：1. 比我预想的要好\n",
    "   2. 三点改进：\n",
    "     1). 训练数据时发现模型有点过拟合了，可以卡在全连接层增加dropout\n",
    "     2). 可以通过增强数据来解决过拟合问题\n",
    "     3). 可以尝试不同的优化器，在训练时出现梯度消失问题的话。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5\n",
      "94658560/94653016 [==============================] - 1s 0us/step\n",
      "in/045.Cardigan_welsh_corgi\n",
      "in/076.Golden_retriever\n",
      "in/005.Alaskan_malamute\n",
      "This is not dog or human pic\n",
      "in/056.Dachshund\n"
     ]
    }
   ],
   "source": [
    "## TODO: 在你的电脑上，在步骤6中，至少在6张图片上运行你的算法。\n",
    "## 自由地使用所需的代码单元数吧\n",
    "test_img = ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg','6.jpg']\n",
    "for  i in test_img:\n",
    "    print(human_dog(i))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意: 当你写完了所有的代码，并且回答了所有的问题。你就可以把你的 iPython Notebook 导出成 HTML 文件。你可以在菜单栏，这样导出File -> Download as -> HTML (.html)把这个 HTML 和这个 iPython notebook 一起做为你的作业提交。**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
